package it.giuseppetrisciuoglio.lyrics.http;

import it.giuseppetrisciuoglio.lyrics.persistence.entity.CacheResponse;
import it.giuseppetrisciuoglio.lyrics.persistence.repository.CacheResponseRepository;

import java.io.IOException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class HttpReader {

	@Autowired
	private HttpHost proxy;
	
	@Autowired
	private CacheResponseRepository cacheResponseRepository;
	
	@Autowired
	private HttpResponseCacheHandler httpResponseCacheHandler;

	@Value("${http.userAgent}")
	private String userAgent;

	@Value("${http.defaultCharset}")
	private String defaultCharset;

	@Value("${http.connectionTimeoutMillis}")
	private int connectionTimeoutMillis;

	@Value("${http.socketTimeoutMillis}")
	private int socketTimeoutMillis;

	@Value("${proxy.enabled}")
	private boolean proxyEnabled;
	
	private final transient Logger log = LoggerFactory.getLogger(getClass());

	public HttpReader() {
		super();
	}

	public String getResponse(String url) throws IOException {
		log.debug("getResponse(): url={}", url);
		if (url == null){
			throw new IllegalArgumentException("Parameter 'url' is null");
		}
		
		CacheResponse cacheResponse = cacheResponseRepository.findOne(url);
		if (cacheResponse != null){
			log.debug("getResponse(): this url '{}' already process, returning cache payload. ", url);
			return cacheResponse.getPayload();
		}
		
		String response = null;
		HttpGet httpGet = new HttpGet(url);
		httpGet.setHeader("X-Forwarded-For", proxy.getHostName());
		HttpClient client = getHttpClient();
		try {
			
			response = client.execute(httpGet, getResponseHandler());
			httpResponseCacheHandler.saveCacheResponse(url, response, 200);
			
		} catch (HttpResponseException e) {
			log.error("getResponse(): exception={}", e.getMessage());
			httpResponseCacheHandler.saveCacheResponse(url, null, e.getStatusCode());
			throw e;
		} catch (Exception e) {
			log.error("getResponse(): exception={}", e.getMessage());
			throw new IOException(e);
		} finally {
			client.getConnectionManager().shutdown();
		}
		log.debug("getResponse(): is ok, returing.");
		return response;
	}

	private HttpClient getHttpClient() {
		HttpClient client = new DefaultHttpClient();
		if (proxyEnabled) {
			log.debug("getResponse(): Proxy is enabled.");
			client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
		}
		client.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, defaultCharset);
		client.getParams().setParameter(CoreProtocolPNames.USER_AGENT, userAgent);
		HttpConnectionParams.setConnectionTimeout(client.getParams(), connectionTimeoutMillis);
		HttpConnectionParams.setSoTimeout(client.getParams(), socketTimeoutMillis);
		return client;
	}

	private ResponseHandler<String> getResponseHandler() {
		ResponseHandler<String> responseHandler = new BasicResponseHandler() {
			@Override
			public String handleResponse(HttpResponse response) throws HttpResponseException, IOException {
				StatusLine statusLine = response.getStatusLine();
				if (statusLine.getStatusCode() >= 300) {
					throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
				}
				HttpEntity entity = response.getEntity();
				return entity == null ? null : EntityUtils.toString(entity, defaultCharset);
			}
		};
		return responseHandler;
	}

}
